package com.dmj.sqldsl.wrapper;

import com.dmj.sqldsl.builder.DeleteBuilder;
import com.dmj.sqldsl.builder.DslQueryBuilder;
import com.dmj.sqldsl.builder.UpdateWhereBuilder;
import com.dmj.sqldsl.builder.column.ColumnBuilder;
import com.dmj.sqldsl.builder.column.DateRange;
import com.dmj.sqldsl.builder.column.LikeValue;
import com.dmj.sqldsl.builder.column.type.BooleanLambda;
import com.dmj.sqldsl.builder.column.type.ColumnLambda;
import com.dmj.sqldsl.builder.column.type.DateLambda;
import com.dmj.sqldsl.builder.column.type.NumberLambda;
import com.dmj.sqldsl.builder.column.type.StringLambda;
import com.dmj.sqldsl.builder.condition.ConditionBuilders;
import com.dmj.sqldsl.builder.condition.ConditionsBuilder;
import java.util.Collection;
import java.util.function.Consumer;

public abstract class Wrapper<T> {

  private final Class<T> entityClass;
  private ConditionsBuilder conditionsBuilder;

  public Wrapper(Class<T> entityClass) {
    this.entityClass = entityClass;
    this.conditionsBuilder = ConditionBuilders.empty();
  }

  public Wrapper<T> eq(StringLambda<T> lambda, String value) {
    this.conditionsBuilder.eq(lambda, value);
    return this;
  }

  public Wrapper<T> eq(NumberLambda<T> lambda, Number value) {
    this.conditionsBuilder.eq(lambda, value);
    return this;
  }

  public Wrapper<T> eq(BooleanLambda<T> lambda, Boolean value) {
    this.conditionsBuilder.eq(lambda, value);
    return this;
  }

  public Wrapper<T> eq(ColumnBuilder<T, Boolean> columnBuilder, Boolean value) {
    this.conditionsBuilder.eq(columnBuilder, value);
    return this;
  }

  public Wrapper<T> eq(ColumnBuilder<T, String> columnBuilder, String value) {
    this.conditionsBuilder.eq(columnBuilder, value);
    return this;
  }

  public Wrapper<T> eq(ColumnBuilder<T, Number> columnBuilder, Number value) {
    this.conditionsBuilder.eq(columnBuilder, value);
    return this;
  }

  public Wrapper<T> ne(StringLambda<T> lambda, String value) {
    this.conditionsBuilder.ne(lambda, value);
    return this;
  }

  public Wrapper<T> ne(NumberLambda<T> lambda, Number value) {
    this.conditionsBuilder.ne(lambda, value);
    return this;
  }

  public Wrapper<T> ne(BooleanLambda<T> lambda, Boolean value) {
    this.conditionsBuilder.ne(lambda, value);
    return this;
  }

  public Wrapper<T> ne(ColumnBuilder<T, Boolean> columnBuilder, Boolean value) {
    this.conditionsBuilder.ne(columnBuilder, value);
    return this;
  }

  public Wrapper<T> ne(ColumnBuilder<T, String> columnBuilder, String value) {
    this.conditionsBuilder.ne(columnBuilder, value);
    return this;
  }

  public Wrapper<T> ne(ColumnBuilder<T, Number> columnBuilder, Number value) {
    this.conditionsBuilder.ne(columnBuilder, value);
    return this;
  }

  public Wrapper<T> gt(StringLambda<T> lambda, String value) {
    this.conditionsBuilder.gt(lambda, value);
    return this;
  }

  public Wrapper<T> gt(NumberLambda<T> lambda, Number value) {
    this.conditionsBuilder.gt(lambda, value);
    return this;
  }

  public Wrapper<T> gt(BooleanLambda<T> lambda, Boolean value) {
    this.conditionsBuilder.gt(lambda, value);
    return this;
  }

  public Wrapper<T> gt(ColumnBuilder<T, Boolean> columnBuilder, Boolean value) {
    this.conditionsBuilder.gt(columnBuilder, value);
    return this;
  }

  public Wrapper<T> gt(ColumnBuilder<T, String> columnBuilder, String value) {
    this.conditionsBuilder.gt(columnBuilder, value);
    return this;
  }

  public Wrapper<T> gt(ColumnBuilder<T, Number> columnBuilder, Number value) {
    this.conditionsBuilder.gt(columnBuilder, value);
    return this;
  }

  public Wrapper<T> ge(StringLambda<T> lambda, String value) {
    this.conditionsBuilder.ge(lambda, value);
    return this;
  }

  public Wrapper<T> ge(NumberLambda<T> lambda, Number value) {
    this.conditionsBuilder.ge(lambda, value);
    return this;
  }

  public Wrapper<T> ge(BooleanLambda<T> lambda, Boolean value) {
    this.conditionsBuilder.ge(lambda, value);
    return this;
  }

  public Wrapper<T> ge(ColumnBuilder<T, Boolean> columnBuilder, Boolean value) {
    this.conditionsBuilder.ge(columnBuilder, value);
    return this;
  }

  public Wrapper<T> ge(ColumnBuilder<T, String> columnBuilder, String value) {
    this.conditionsBuilder.ge(columnBuilder, value);
    return this;
  }

  public Wrapper<T> ge(ColumnBuilder<T, Number> columnBuilder, Number value) {
    this.conditionsBuilder.ge(columnBuilder, value);
    return this;
  }

  public Wrapper<T> lt(StringLambda<T> lambda, String value) {
    this.conditionsBuilder.lt(lambda, value);
    return this;
  }

  public Wrapper<T> lt(NumberLambda<T> lambda, Number value) {
    this.conditionsBuilder.lt(lambda, value);
    return this;
  }

  public Wrapper<T> lt(BooleanLambda<T> lambda, Boolean value) {
    this.conditionsBuilder.lt(lambda, value);
    return this;
  }

  public Wrapper<T> lt(ColumnBuilder<T, Boolean> columnBuilder, Boolean value) {
    this.conditionsBuilder.lt(columnBuilder, value);
    return this;
  }

  public Wrapper<T> lt(ColumnBuilder<T, String> columnBuilder, String value) {
    this.conditionsBuilder.lt(columnBuilder, value);
    return this;
  }

  public Wrapper<T> lt(ColumnBuilder<T, Number> columnBuilder, Number value) {
    this.conditionsBuilder.lt(columnBuilder, value);
    return this;
  }

  public Wrapper<T> le(StringLambda<T> lambda, String value) {
    this.conditionsBuilder.le(lambda, value);
    return this;
  }

  public Wrapper<T> le(NumberLambda<T> lambda, Number value) {
    this.conditionsBuilder.le(lambda, value);
    return this;
  }

  public Wrapper<T> le(BooleanLambda<T> lambda, Boolean value) {
    this.conditionsBuilder.le(lambda, value);
    return this;
  }

  public Wrapper<T> le(ColumnBuilder<T, Boolean> columnBuilder, Boolean value) {
    this.conditionsBuilder.le(columnBuilder, value);
    return this;
  }

  public Wrapper<T> le(ColumnBuilder<T, String> columnBuilder, String value) {
    this.conditionsBuilder.le(columnBuilder, value);
    return this;
  }

  public Wrapper<T> le(ColumnBuilder<T, Number> columnBuilder, Number value) {
    this.conditionsBuilder.le(columnBuilder, value);
    return this;
  }

  public Wrapper<T> in(NumberLambda<T> lambda, Collection<Number> valueList) {
    this.conditionsBuilder.in(lambda, valueList);
    return this;
  }

  public Wrapper<T> in(StringLambda<T> lambda, Collection<String> valueList) {
    this.conditionsBuilder.in(lambda, valueList);
    return this;
  }

  public Wrapper<T> in(NumberLambda<T> lambda, Number... valueList) {
    this.conditionsBuilder.in(lambda, valueList);
    return this;
  }

  public Wrapper<T> in(StringLambda<T> lambda, String... valueList) {
    this.conditionsBuilder.in(lambda, valueList);
    return this;
  }

  public Wrapper<T> notIn(NumberLambda<T> lambda, Collection<Number> valueList) {
    this.conditionsBuilder.notIn(lambda, valueList);
    return this;
  }

  public Wrapper<T> notIn(StringLambda<T> lambda, Collection<String> valueList) {
    this.conditionsBuilder.notIn(lambda, valueList);
    return this;
  }

  public Wrapper<T> notIn(NumberLambda<T> lambda, Number... valueList) {
    this.conditionsBuilder.notIn(lambda, valueList);
    return this;
  }

  public Wrapper<T> notIn(StringLambda<T> lambda, String... valueList) {
    this.conditionsBuilder.notIn(lambda, valueList);
    return this;
  }

  public Wrapper<T> like(StringLambda<T> lambda, LikeValue likeValue) {
    this.conditionsBuilder.like(lambda, likeValue);
    return this;
  }

  public Wrapper<T> like(ColumnBuilder<T, String> lambda, LikeValue likeValue) {
    this.conditionsBuilder.like(lambda, likeValue);
    return this;
  }

  public Wrapper<T> notLike(StringLambda<T> lambda, LikeValue likeValue) {
    this.conditionsBuilder.notLike(lambda, likeValue);
    return this;
  }

  public Wrapper<T> notLike(ColumnBuilder<T, String> lambda, LikeValue likeValue) {
    this.conditionsBuilder.notLike(lambda, likeValue);
    return this;
  }

  public Wrapper<T> between(DateLambda<T> lambda, DateRange range) {
    this.conditionsBuilder.between(lambda, range);
    return this;
  }

  public Wrapper<T> and() {
    this.conditionsBuilder.and();
    return this;
  }

  public Wrapper<T> and(Consumer<Wrapper<T>> consumer) {
    Wrapper<T> newWrapper = createNewWrapper();
    consumer.accept(newWrapper);
    this.conditionsBuilder.and(newWrapper.getConditionsBuilder());
    return this;
  }

  public Wrapper<T> or() {
    this.conditionsBuilder.or();
    return this;
  }

  public Wrapper<T> or(Consumer<Wrapper<T>> consumer) {
    Wrapper<T> newWrapper = createNewWrapper();
    consumer.accept(newWrapper);
    this.conditionsBuilder.or(newWrapper.getConditionsBuilder());
    return this;
  }

  protected <R> Wrapper<T> orderBy(ColumnLambda<T, R> lambda, boolean isAsc) {
    return this;
  }

  @SuppressWarnings("unchecked")
  public <R> Wrapper<T> groupBy(ColumnLambda<T, R>... lambdas) {
    return this;
  }

  public Wrapper<T> having(Consumer<Wrapper<T>> wrapperConsumer) {
    return this;
  }

  public Wrapper<T> limit(int size) {
    return this;
  }

  protected ConditionsBuilder getConditionsBuilder() {
    return this.conditionsBuilder;
  }

  protected Class<T> getEntityClass() {
    return this.entityClass;
  }

  protected DslQueryBuilder toQueryBuilder() {
    return null;
  }

  protected DeleteBuilder toDeleteBuilder() {
    return null;
  }

  public UpdateWhereBuilder<T> toUpdateBuilder() {
    return null;
  }

  protected abstract Wrapper<T> createNewWrapper();
}
